import { Injectable, HttpException, HttpStatus, Request } from '@nestjs/common';
import { CreateAdminDto, LoginAdminDto, RoleAdminDto, SetPwdDto } from './dto/create-admin.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, DataSource, Not } from 'typeorm';
import { Admin } from './entities/admin.entity';
import { RoleAdmin } from './entities/roleAdmin.entity';
import * as bcrypt from 'bcrypt';
import { throwCustomException } from 'src/utils/fun';
// import { Cache } from 'cache-manager';
// import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { MakeToken } from 'src/utils/token';
// import { RedisService } from 'src/redis/redis.service';
import { format } from "date-fns";
@Injectable()
export class AdminService {
  constructor(
    @InjectRepository(Admin)
    private readonly adminRepository: Repository<Admin>,
    @InjectRepository(RoleAdmin)
    private readonly roleAdminRepository: Repository<RoleAdmin>,
    private readonly dataSource: DataSource,
    // private RedisService: RedisService
    //@Inject(CACHE_MANAGER) private readonly cacheManager: Cache
  ) {}
  async create(createAdminDto: CreateAdminDto) {
    try{
      let salt = '';
      let params = {}
      if(!createAdminDto.id){//添加
        const isExists = await this.isUserExists({account: createAdminDto.account})
        if(isExists){
          throwCustomException('账号已存在')
        }
        salt = await bcrypt.genSalt();
        createAdminDto.password = await bcrypt.hash(createAdminDto.password, salt);
        params = {
          ...createAdminDto,
          salt,
          status: 0,
        }
      }else{
        const isExists = await this.isUserExists({account: createAdminDto.account,id: Not(createAdminDto.id)})
        if(isExists){
          throwCustomException('账号已存在')
        }
        const { password, ...newVals } = createAdminDto
        params = { ...newVals }
      }
      return await this.adminRepository.save({
        ...params,
      })
    } catch (error) {
      throw new HttpException(error.message, error.status);
    }
    
  }
  async isUserExists(obj){
    const result = await this.adminRepository.findOne({ 
      where: obj
    });
    return !!result
  }

  async login(LoginAdminDto: LoginAdminDto, realIp){
    const { account, password: newPassword } = LoginAdminDto
    const result = await this.adminRepository.findOne({ where: { account } })
    if(result){
      const { salt, password, id } = result
      const npassword = await bcrypt.hash(newPassword, salt);
      if(npassword !== password){
        throwCustomException('密码错误')
      }
      try {
        const time = format(new Date(), 'yyyy-MM-dd HH:mm:ss')
        this.adminRepository.update(id, { lastLoginTime: time, lastLoginIp: realIp });
        const token = await MakeToken(result)
        return {
          userId: result.id,
          token,
          userName: result.account,
          nickName: result.nickname,
          avatar: ''
        }
      } catch (error) {
        throw new HttpException(error.message, HttpStatus.INTERNAL_SERVER_ERROR);
      }
    }else{
      throwCustomException('账号不存在')
    }
  }

  async setPwd(query: SetPwdDto) {
    try {
      const { id, newPassword, confirmPassword } = query;
      if (newPassword !== confirmPassword) {
        throwCustomException('两次密码不一致')
      }
      const admin = await this.adminRepository.findOne({ where: { id } });
      if (!admin) {
        throwCustomException('管理员不存在')
        return
      }
      const salt = await bcrypt.genSalt();
      const hashedPassword = await bcrypt.hash(newPassword, salt);
      admin.password = hashedPassword;
      admin.salt = salt;
      await this.adminRepository.save(admin);
      return { message: '密码更新成功' };
    } catch (error) {
      // 生产环境建议统一返回模糊错误信息
      const statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
  
      throw new HttpException(error.message, statusCode);
    }
  }
  async setRandPwd(){

  }

  async findAll(query) {
    try {
      const { page = 1, limit = 10, ...formData } = query
      return await this.adminRepository.findAndCount({
        select: ['id','account','mobile','nickname','status','departmentId','lastLoginTime','lastLoginIp','createTime','updateTime'],
        where: {
          ...formData
        },
        skip: (page - 1) * limit,
        take: limit
      });
    } catch (error) {
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
    
  }
  async delete(id: string) {
    try {
      return await this.adminRepository.delete(id);
    } catch (error) {
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  async findAllByRole(roleId) {
    try {
      return await this.roleAdminRepository
      // .find({
      //   where:{roleId}
      // })
      .createQueryBuilder('roleAdmin')
      .leftJoinAndSelect('roleAdmin.admin','admin')
      .select('roleAdmin.roleId, admin.nickname, admin.mobile, admin.account, admin.id')
      .where("roleAdmin.roleId = :roleId", {roleId})
      .getRawMany()
    } catch (error) {
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
    
  }

  async saveRoleAdmin(roleAdminDto: RoleAdminDto) {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();
    try {
      const existingRoles = await this.roleAdminRepository.find({
        where: { roleId: roleAdminDto.roleId },
      });
      const existingAdminIds = existingRoles.map((r) => r.adminId);

      const addData = roleAdminDto.adminIds.filter((id) => !existingAdminIds.includes(id));
      const delData = existingAdminIds.filter((id) => !roleAdminDto.adminIds.includes(id));

      if (addData.length > 0) {
        await queryRunner.manager.insert(
          RoleAdmin,
          addData.map((adminId) => ({
            roleId: roleAdminDto.roleId,
            adminId,
          }))
        );
      }

      if (delData.length > 0) {
        await queryRunner.manager.delete(RoleAdmin, {
          roleId: roleAdminDto.roleId,
          adminId: delData,
        });
      }

      await queryRunner.commitTransaction();
      return true;
    } catch (error) {
      await queryRunner.rollbackTransaction();
      throw new HttpException(error.message, error.status, {
        cause: error,
      });
    } finally {
      await queryRunner.release();
    }
  }

  async getRoleByAdmin(adminId){
    try {
      if (typeof adminId !== 'number' || isNaN(adminId)) {
        throw new HttpException('Invalid adminId', HttpStatus.BAD_REQUEST);
      }
      return await this.roleAdminRepository.find({ where:{ adminId } })
    } catch (error) {
      throw new HttpException(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }
}
